#include <iostream>
#include <string>
#include <functional>
#include <vector>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/types.h>

#include "Log.hpp"
#include "InetAddr.hpp"
#include "LockGuard.hpp"

using task_t = std::function<void()>;

class Route
{
public:
    Route()
    {
        pthread_mutex_init(&_mutex, nullptr);
    }
    void CheckOnlineuser(const InetAddr &who)
    {
        LockGuard lock(&_mutex);
        for (auto &user : _online_user)
        {
            if (who == user)
                return;
        }
        _online_user.push_back(who);
    }

    void Offline(const InetAddr &who)
    {
        LockGuard lock(&_mutex);
        auto iter = _online_user.begin();
        for (; iter != _online_user.end(); iter++)
        {
            if (*iter == who)
            {
                _online_user.erase(iter);
                break;
            }
        }
    }

    void ForwordHelper(int sockfd, const std::string &message, const InetAddr &who)
    {
        LockGuard lock(&_mutex);
        for (auto &user : _online_user)
        {
            if (who == user)
                continue;
            struct sockaddr_in peer = user.Addr();
            sendto(sockfd, message.c_str(), message.size(), 0, (struct sockaddr *)&peer, sizeof(peer));
        }
    }

    void Forword(int sockfd, const std::string &message, const InetAddr &who)
    {
        CheckOnlineuser(who);

        if (message == "QUIT" || message == "Q")
        {
            Offline(who);
        }

        // ForwordHelper(sockfd, message, who);
        task_t t = bind(&Route::ForwordHelper, this, sockfd, message, who);
        ThreadPool<task_t>::GetInstance()->Equeue(t);
    }
    ~Route()
    {
        pthread_mutex_destroy(&_mutex);
    }

private:
    std::vector<InetAddr> _online_user;
    pthread_mutex_t _mutex;
};